/**
 * @file xButton.c
 * @author eric
 * @brief
 * @version 0.1
 * @date 2024-09-19
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <string.h>
#include "xbutton.h"

/************************************************************************
 * 按键逻辑：
 * 1，按下按键，触发 B_EVENT_DOWN
 * 2，松开按键，触发 B_EVENT_UP
 * 3，按下按键，并松开，持续时长达到 TICKS_SHORT ，触发 B_EVENT_CLICK
 * 4，松开按键，持续时长达到 TICKS_IDEL ，按键状态重置
 * 5，松开-按下，间隔< TICKS_IDEL ,触发 B_EVENT_REPEAT
 ************************************************************************/

#define EVENT_CB(ev)                                           \
    do {                                                       \
        if (handle->cb[ev]) handle->cb[ev]((button_t*)handle); \
    } while (0);

typedef struct button_node list_node_t;

// button_state
enum
{
    S_IDLE = 0,
    S_DOWN,
    S_UP_FAST,
    S_UP,
};

static uint8_t          is_init = 0;
static struct list_head head;

void button_init(button_t* handle, read_key_cb read_key, uint8_t active_level)
{
    if (is_init == 0) {
        INIT_LIST_HEAD(&head);
        is_init = 1;
    }

    memset(handle, 0, sizeof(button_t));

    handle->event        = (uint8_t)B_EVENT_NONE;
    handle->read_key     = read_key;
    handle->level        = handle->read_key();
    handle->active_level = active_level;
}

void button_bind(button_t* handle, button_event_t event, event_cb cb)
{
    handle->cb[event] = cb;
}

button_event_t button_get_event(button_t* handle)
{
    return (button_event_t)(handle->event);
}

uint8_t button_is_active(button_t* handle)
{
    return (handle->level == handle->active_level);
}

void button_handler(button_t* handle)
{
    uint8_t read_level = handle->read_key();

    // 按键变化
    if (read_level != handle->level) {
        // 按键消抖，连续读取3次，大约15ms
        if (handle->debounce_cnt >= TICKS_DEBOUNCE) {
            handle->level        = read_level;   // 按键锁定
            handle->debounce_cnt = 0;
        } else {
            handle->debounce_cnt++;
        }
    } else {
        handle->debounce_cnt = 0;
    }

    // 状态机
    switch (handle->state) {
    case S_IDLE: handle->repeat = 0;
    case S_UP_FAST:
        handle->ticks = 0;
        handle->event = (uint8_t)B_EVENT_NONE;
        handle->state = S_UP;
    case S_UP:

        if (handle->level == handle->active_level) {   // 按键触发
            handle->event = (uint8_t)B_EVENT_DOWN;
            EVENT_CB(B_EVENT_DOWN);

            handle->repeat++;
            handle->ticks = 0;
            handle->state = S_DOWN;
        } else if (handle->ticks > TICKS_IDEL) {
            if (handle->repeat == 2) {
                handle->event = (uint8_t)B_EVENT_DOUBLE_CLICK;
                EVENT_CB(B_EVENT_DOUBLE_CLICK);
            } else if (handle->repeat == 1) {
                handle->event = (uint8_t)B_EVENT_CLICK;
                EVENT_CB(B_EVENT_CLICK);
            } else {
                handle->event = (uint8_t)B_EVENT_NONE;
            }

            handle->repeat = 0;
            handle->ticks  = 0;
            handle->state  = S_IDLE;
        } else {
            if ((handle->ticks == 0) && (handle->repeat > 1)) {   // 按键变化时，仅触发一次
                handle->event = (uint8_t)B_EVENT_REPEAT;
                EVENT_CB(B_EVENT_REPEAT);
            } else {
                handle->event = (uint8_t)B_EVENT_NONE;
            }

            handle->ticks++;   // 当前状态计数...
        }
        break;
    case S_DOWN:
        if (handle->level != handle->active_level) {   // 按键释放
            // 按键保持，持续是否达到 TICKS_SHORT
            if (handle->ticks >= TICKS_LONG) {
                handle->state = S_IDLE;
            } else if (handle->ticks >= TICKS_SHORT) {
                handle->state = S_UP;
            } else {   // 如果按键很短时间内弹起，则触发S_UP_FAST，用于repeat计数操作
                handle->state = S_UP_FAST;
            }

            handle->ticks = 0;
            handle->event = (uint8_t)B_EVENT_UP;
            EVENT_CB(B_EVENT_UP);
        } else if (handle->ticks == TICKS_LONG) {   // 触发长按
            handle->event = (uint8_t)B_EVENT_PRESS_START;
            EVENT_CB(B_EVENT_PRESS_START);

            handle->ticks++;                       // 当前状态计数...
        } else if (handle->ticks > TICKS_LONG) {   // 长按锁定
            if ((handle->ticks % TICKS_HOLD_INTERVAL) == 1) {
                handle->event = (uint8_t)B_EVENT_PRESS_HOLD;
                EVENT_CB(B_EVENT_PRESS_HOLD);
            }

            handle->ticks++;   // 当前状态计数...
        } else {
            handle->event = (uint8_t)B_EVENT_NONE;
            handle->ticks++;   // 当前状态计数...
        }
        break;
    default:
        handle->ticks  = 0;
        handle->repeat = 0;
        handle->event  = (uint8_t)B_EVENT_NONE;
        handle->state  = S_IDLE;
        break;
    }
}

int button_start(button_t* handle)
{
    list_node_t* node    = NULL;
    int          is_find = 0;

    if (is_init == 0) {
        return -1;
    }

    // 是否已经添加？
    list_for_each_entry(node, &head, list, button_t)
    {
        if (node == handle) {
            is_find = 1;
        }
    }
    // 添加按键
    if (is_find == 0) {
        list_add(&(handle->list), &head);
    }

    return 0;
}

int button_stop(button_t* handle)
{
    list_node_t* node    = NULL;
    list_node_t* n       = NULL;
    int          is_find = 0;

    if (is_init == 0) {
        return -1;
    }

    list_for_each_entry_safe(node, n, &head, list, button_t)
    {
        if (node == handle) {
            is_find = 1;
            list_del(&(node->list));
        }
    }

    if (is_find == 0) {
        return -1;
    } else {
        return 0;
    }
}

void button_loops(void)
{
    list_node_t* node = NULL;

    if (is_init == 0) {
        return;
    }

    list_for_each_entry(node, &head, list, button_t)
    {
        button_handler(node);
    }
}
